import { ICanPickupMoneyElement } from "../configs/CanPickupMoney"
import { GameConfig } from "../configs/GameConfig"
import { Attribute } from "../etc/Attribute"
import { updater } from "../etc/Updater"
import { LevelModuleC, LevelModuleData, LevelModuleS } from "./LevelModule"
import { PlayerModuleS } from "./PlayerModule"

class PickupMoneyMapping {
    private static emptyArray = []
    private static mapping: Map<number, ICanPickupMoneyElement[]>

    static getPickupMoneyIDArrayByKind(kind: number):ICanPickupMoneyElement[] {
        this.mappingChecker()
        // 这个关卡没有金币
        if(!this.mapping.has(kind)) return this.emptyArray
        return this.mapping.get(kind)
    }

    private static mappingChecker() {
        if (this.mapping) return
        this.mapping = new Map()
        for (const cfg of GameConfig.CanPickupMoney.getAllElement()) {
            if (!this.mapping.has(cfg.Kind)) this.mapping.set(cfg.Kind, [])
            this.mapping.get(cfg.Kind).push(cfg)
        }
    }
}

export class PickupMoneyModuleData extends Subdata{
    @Decorator.persistence()
    pickupMoneyArray:number[]

    protected initDefaultData(): void {
        this.pickupMoneyArray = []
    }
}

class PickupMoney{
    static moneyPrototypeGUID = '1D25A314'
    cfg:ICanPickupMoneyElement
    moneyGameObject:GameObject | undefined
    levelGameObject:GameObject

    resetCfg(cfg:ICanPickupMoneyElement){
        this.cfg = cfg

        if(this.moneyGameObject){
            GameObjPool.despawn(this.moneyGameObject)
        }

        let levelCfg = GameConfig.Level.getElement(this.cfg.Kind)

        this.levelGameObject = GameObject.findGameObjectById(levelCfg.LevelGameObjectGUID)

        this.moneyGameObject = GameObjPool.spawn(PickupMoney.moneyPrototypeGUID, GameObjPoolSourceType.Scene)

        this.moneyGameObject.parent = this.levelGameObject

        this.moneyGameObject.localTransform.position = this.cfg.PickupMoneyLocalPosition
    }

    // 未激活
    isDisabled():boolean {
        return this.moneyGameObject == undefined
    }

    disable(){
        if(!this.moneyGameObject) return

        GameObjPool.despawn(this.moneyGameObject)
        this.moneyGameObject = undefined
    }
}

export class PickupMoneyModuleC extends ModuleC<PickupMoneyModuleS, PickupMoneyModuleData>{
    private levelMD:LevelModuleC
    private levelData:LevelModuleData
    private pickupMoneyArray:PickupMoney[] = []

    protected onStart(): void {
        this.levelMD = ModuleService.getModule(LevelModuleC)
        this.levelData = DataCenterC.getData(LevelModuleData)
        this.levelMD.onLevelChanged.add(this.refillCurrentLevelPickupMoney, this)

        let currentPointID = DataCenterC.getData(LevelModuleData).checkPointID
        let currentCheckpointCfg = GameConfig.Checkpoint.getElement(currentPointID)
        this.refillCurrentLevelPickupMoney(currentCheckpointCfg.Kind)
    }

    protected onUpdate(dt: number): void { }

    // TODO 可优化 
    @updater.updateByFrameInterval(15)
    private pickupRecentMoneyChecker(){
        let playerPosition = this.localPlayer.character.worldTransform.position
        for (const pickupMoney of this.pickupMoneyArray) {
            // 未激活
            if(pickupMoney.isDisabled()) continue
            // 距离判定
            let distance = Vector.distance(playerPosition, pickupMoney.moneyGameObject.worldTransform.position)
            if(distance > 250) continue
            // 播放拾取特效 
            EffectService.playAtPosition('151532', pickupMoney.moneyGameObject.worldTransform.position, {
                scale: new Vector(3,3,3),
                rotation: Player.localPlayer.character.worldTransform.rotation
            })
            // 拾取这个金币
            pickupMoney.disable()
            this.server.net_pickup_money(pickupMoney.cfg.ID)
            // 播放金币音效
            SoundService.playSound('136208')
        }
    }

    private refillCurrentLevelPickupMoney(level:number){
        let currentLevelPickupMoneyArray = PickupMoneyMapping.getPickupMoneyIDArrayByKind(level)
        // 隐藏所有金币
        for (const pickupMoney of this.pickupMoneyArray) {
            pickupMoney.disable()
        }
        // 如果池子里金币小于要显示的则填充
        for(let i = this.pickupMoneyArray.length;i < currentLevelPickupMoneyArray.length;i++){
            this.pickupMoneyArray.push(new PickupMoney())
        }
        // 填充没有领取过的金币
        for(let i = 0;i < currentLevelPickupMoneyArray.length;i++){
            let cfg = currentLevelPickupMoneyArray[i]

            if(this.data.pickupMoneyArray.includes(cfg.ID)) continue

            let pickupMoney = this.pickupMoneyArray[i]

            pickupMoney.resetCfg(cfg)
        }
    }
}

export class PickupMoneyModuleS extends ModuleS<PickupMoneyModuleC, PickupMoneyModuleData>{

    protected onStart(): void {
        ModuleService.getModule(LevelModuleS).onPlayerLevelChangeEvent.add(this.onPlayerLevelChanged, this)
    }

    net_pickup_money(moneyCfgID:number){
        if(this.currentData.pickupMoneyArray.includes(moneyCfgID)) return

        this.currentData.pickupMoneyArray.push(moneyCfgID)

        let moneyCfg = GameConfig.CanPickupMoney.getElement(moneyCfgID)

        let playerMD = ModuleService.getModule(PlayerModuleS)
        playerMD.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.money, moneyCfg.MoneyCount)

        console.warn(`玩家拾取金币, 当前关卡拾取总数:${this.currentData.pickupMoneyArray.length}`);
        
        this.currentData.save(true)
    }

    onPlayerLevelChanged(playerID:number){
        // 清空这一关玩家已领取的金币
        let data = this.getPlayerData(playerID)
        data.pickupMoneyArray = []
        data.save(true)
    }
}